/*
 * usb.h
 *
 *  Created on: 11.03.2012
 *      Author: g.kruglov
 */

#ifndef USB_H_
#define USB_H_

#include "kl_lib.h"
#include "usb_defins.h"

#define USB_EP_NUMBER       4   // Number of endpoints used

#define USB_MAX_PKT_SIZE    64

#define ENDP0_RXADDR        (0x40)
#define ENDP0_TXADDR        (0x80)

extern uint8_t SettingsBuf[7];

struct UsbRequest_t {
    uint8_t bmRequestType, bRequest;
    uint16_t wValue, wIndex, wLength;
};

enum EpxState_t {epxDisabled, epxStall, epxNAK, epxValid};

class Endpoint_t {
private:
    // Read/write hardware buffer
    void WriteBuffer(uint8_t *PBuffer, uint16_t ALength);
    void ReadBuffer (uint8_t *PBuffer, uint16_t ALength);
    void SetReg(uint16_t AValue) { *(EP0REG + Indx) = AValue; }
public:
    uint8_t Indx;
    uint8_t *Buf;
    uint32_t Count;
    uint8_t Fill;
    void SetType   (uint16_t AType)    { SetReg((GetReg() & EP_T_MASK) | AType); }
    uint16_t GetReg(void) { return ((uint16_t)(*(EP0REG + Indx))); }
    void SetAddress(uint8_t AAddr)     { SetReg(EP_CTR_RX | EP_CTR_TX | (GetReg() & EPREG_MASK) | AAddr ); }
    // Buffers
    void SetRxCount(uint16_t ACount);
    uint16_t GetRxCount(void)          { return (*pEPRxCount(Indx) & 0x03FF); }
    uint16_t GetTxCount(void)          { return (*pEPTxCount(Indx) & 0x03FF); }
    void SetTxCount(uint16_t ACount)   { *pEPTxCount(Indx) = ACount; }
    void SetRxAddr (uint16_t AAddr)    { *pEPRxAddr(Indx) = AAddr; }
    void SetTxAddr (uint16_t AAddr)    { *pEPTxAddr(Indx) = AAddr; }
    uint16_t GetRxAddr(void)           { return ((uint16_t) *pEPRxAddr(Indx)); }
    uint16_t GetTxAddr(void)           { return ((uint16_t) *pEPTxAddr(Indx)); }
    // States
    void SetTxState(EpxState_t ATxState);
    void SetRxState(EpxState_t ARxState);
    EpxState_t GetTxState(void);
    EpxState_t GetRxState(void);
    void ClearCTR_TX(void) { SetReg(GetReg() & 0xFF7F & EPREG_MASK); }
    void ClearCTR_RX(void) { SetReg(GetReg() & 0x7FFF & EPREG_MASK); }
    void ClearStatusOut(void) { SetReg(EP_CTR_RX | EP_CTR_TX | (GetReg() & EPKIND_MASK)); }
    // Data exchange
    uint16_t WriteData(void);
    void ReceivePkt(void);
    void SendZeroPacket(void) { SetTxCount(0); }
    // Data exchange flags
    bool NewPktReceived, PktTransmitted;
};

class Usb_t {
private:
    // IRQ handlers
    void HandlePkt(void);
    void ErrorPkt(void);
    void Reset(void);
    void CTR_Handler(void); // Correct transfer interrupt handler
    void RST_Handler(void); // RESET interrupt handler
    // Common methods
public:
    // Initialize for send msg
    bool IsConfigured, IsConnected;
    Endpoint_t Ep[4];
    void IConnect(void)     { klPinSet(GPIOA, 15);  }
    void IDisconnect(void)  { klPinClear(GPIOA, 15);}
    void SetDeviceAddress(uint8_t AAddress);
    void Init(void);
    void IRQHandler(void);
    void NewPacketHandler(void);
    void WakeUp(void);
    void Suspend(void);

    // Maintance
    void Task(void);
    void Send(uint8_t *PBuf, uint32_t ACount);
};

// USB interrupt handler
extern "C" {
void USB_LP_CAN1_RX0_IRQHandler(void);
}

extern Usb_t Usb;

#endif /* USB_H_ */
